Skip to content

Autopudate#162

Merged
aojea merged 17 commits into
google:mainfrom
aojea:autopudate
Jun 29, 2026
Merged

Autopudate#162
aojea merged 17 commits into
google:mainfrom
aojea:autopudate

Conversation

@aojea

@aojea aojea commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request removes unused imports and the fallback re-enrollment logic from the middleware, and updates the verification cache key to include the protocol and target to prevent authorization cache bypasses. It also adds a unit test to verify this fix. The review feedback suggests using a null byte (\x00) instead of a colon (:) as a delimiter in the cache key to prevent potential collision attacks, and closing the pipe writer in the test goroutine to prevent potential test hangs.

Comment thread cmd/sam-node/middleware.go Outdated
// Check verification cache
tokenHash := sha256.Sum256(authFrame.Biscuit)
hashStr := hex.EncodeToString(tokenHash[:]) + ":" + remotePeer.String()
hashStr := hex.EncodeToString(tokenHash[:]) + ":" + remotePeer.String() + ":" + reqCtx.Protocol + ":" + reqCtx.Target

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Using a colon (:) as a delimiter for concatenating multiple fields in the cache key can lead to potential cache key collisions if any of the fields (such as reqCtx.Protocol or reqCtx.Target) contain colons. Since reqCtx.Target is derived from the user-controlled authFrame.TargetService, a malicious client could craft a target service name containing colons to collide with another cached authorization entry.

To prevent delimiter collision attacks, use a null byte (\x00) as the separator, as it cannot legitimately appear in standard protocol names or target services.

Suggested change
hashStr := hex.EncodeToString(tokenHash[:]) + ":" + remotePeer.String() + ":" + reqCtx.Protocol + ":" + reqCtx.Target
hashStr := hex.EncodeToString(tokenHash[:]) + "\x00" + remotePeer.String() + "\x00" + reqCtx.Protocol + "\x00" + reqCtx.Target

Comment thread cmd/sam-node/middleware_test.go
@aojea

aojea commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request removes the fallback re-enrollment logic from the middleware and cleans up its associated integration tests. Additionally, it addresses a potential security vulnerability by including the protocol and target in the verification cache key, separated by null delimiters, to prevent authorization cache bypass. A new unit test has been added to verify this cache bypass protection. No review comments were provided, so there is no additional feedback.

aojea added 6 commits June 29, 2026 08:24
…sport

- Move MCP endpoints to listen cleanly on /mcp
- Fallback to unauthenticated HTTP sidecar when running without identity
- Add get_login_instructions tool and help_user_login prompt for graceful failure
- Remove --stdio flag and StdioTransport logic
- Fix E2E test timeout race condition in policy.bats
- Update all documentation and test cases to use the new /mcp endpoint
@aojea

aojea commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies the MCP endpoint URL from /mcp/events to /mcp across the codebase, introduces an unauthenticated sidecar server mode when starting a node without an identity, adds cross-mesh discovery tools with pagination support, and refactors the Biscuit authentication middleware to prevent cache bypass issues. The review feedback highlights a potential panic in the pagination logic if a negative cursor is provided, a security vulnerability due to missing HTTP timeouts on the new unauthenticated sidecar server, and a loose assertion in the new E2E mesh test script.

Comment thread cmd/sam-node/mcp_handlers.go Outdated
Comment thread cmd/sam-node/sidecar.go
Comment on lines +130 to +132
server := &http.Server{
Handler: mux,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The newly introduced startUnauthSidecarServer initializes an http.Server without setting any timeouts (ReadTimeout, WriteTimeout, IdleTimeout). This leaves the server vulnerable to Slowloris attacks and resource exhaustion. It is highly recommended to configure reasonable timeouts.

	server := &http.Server{
		Handler:      mux,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
		IdleTimeout:  120 * time.Second,
	}

Comment thread development/kind/test-mesh-e2e.sh Outdated
aojea and others added 4 commits June 29, 2026 11:46
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@aojea

aojea commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies the MCP endpoint path from /mcp/events to /mcp across all configuration files, documentation, and tests. It also introduces support for starting an unauthenticated sidecar server when a node is run without an identity, enabling enrollment over MCP. Additionally, new cross-mesh discovery tools and prompts have been added (find_remote_resources, read_remote_resource, find_remote_prompts, and get_remote_prompt) along with pagination support. Finally, a security bug in the authorization cache has been resolved by including the protocol and target in the cache key. Feedback on these changes highlights potential nil pointer dereferences when parsing remote resources and prompts, as well as an anti-pattern of using defer inside a loop in handleReadRemoteResource.

Comment thread cmd/sam-node/mcp_handlers.go Outdated
Comment on lines +741 to +749
listRes, err := session.ListResources(ctx, &mcp.ListResourcesParams{})
if err == nil && listRes != nil {
for _, r := range listRes.Resources {
// Namespace the URI scheme or name if we want, but resources are URIs.
// We'll prefix the Name to indicate origin.
r.Name = svc.Name + "." + r.Name
allResources = append(allResources, r)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

In fetchRemoteResourceCatalogue, there is no check to ensure that the resource pointer r is not nil. If a remote peer returns a list containing null elements, this will cause a nil pointer dereference panic, crashing the node. We should add a defensive nil check.

		listRes, err := session.ListResources(ctx, &mcp.ListResourcesParams{})
		if err == nil && listRes != nil {
			for _, r := range listRes.Resources {
				if r == nil {
					continue
				}
				// Namespace the URI scheme or name if we want, but resources are URIs.
				// We'll prefix the Name to indicate origin.
				r.Name = svc.Name + "." + r.Name
				allResources = append(allResources, r)
			}
		}

Comment thread cmd/sam-node/mcp_handlers.go Outdated
Comment on lines +953 to +959
listRes, err := session.ListPrompts(ctx, &mcp.ListPromptsParams{})
if err == nil && listRes != nil {
for _, p := range listRes.Prompts {
p.Name = svc.Name + "." + p.Name
allPrompts = append(allPrompts, p)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

In fetchRemotePromptCatalogue, there is no check to ensure that the prompt pointer p is not nil. If a remote peer returns a list containing null elements, this will cause a nil pointer dereference panic, crashing the node. We should add a defensive nil check.

		listRes, err := session.ListPrompts(ctx, &mcp.ListPromptsParams{})
		if err == nil && listRes != nil {
			for _, p := range listRes.Prompts {
				if p == nil {
					continue
				}
				p.Name = svc.Name + "." + p.Name
				allPrompts = append(allPrompts, p)
			}
		}

Comment thread cmd/sam-node/mcp_handlers.go Outdated
Comment on lines +837 to +848
if err == nil && res != nil && len(res.Contents) > 0 {
defer cleanup()

// Marshal the contents
data, _ := json.Marshal(res.Contents)
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: string(data)},
},
}, nil, nil
}
cleanup()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In handleReadRemoteResource, defer cleanup() is used inside a for loop. In Go, defer statements are evaluated when the surrounding function returns, not when the loop block ends. Although the function returns immediately in this branch, using defer inside a loop is a known anti-pattern and can lead to resource leaks if the code is refactored in the future to not return immediately. It is cleaner and safer to call cleanup() directly.

Suggested change
if err == nil && res != nil && len(res.Contents) > 0 {
defer cleanup()
// Marshal the contents
data, _ := json.Marshal(res.Contents)
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: string(data)},
},
}, nil, nil
}
cleanup()
if err == nil && res != nil && len(res.Contents) > 0 {
cleanup()
// Marshal the contents
data, _ := json.Marshal(res.Contents)
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: string(data)},
},
}, nil, nil
}
cleanup()

@aojea

aojea commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies the MCP endpoint path from /mcp/events to /mcp across the codebase, documentation, and tests. It also introduces an unauthenticated sidecar server that starts when a node runs without an identity, providing enrollment instructions over MCP, and removes the fallback re-enrollment logic from the authorization middleware. Feedback on these changes highlights two issues: first, a bug in the newly added E2E test script (test-mesh-e2e.sh) where the jq filter incorrectly expects an items key from the find_remote_tools output; second, a logic issue in main.go where the fallback for displayHub will not trigger because hubAddr is never empty due to its default value.

Comment on lines +51 to +53
peer="$(printf '%s' "$tools" \
| jq -r '.items[]? | select(.tool_name=="calculator.add") | .peer_id' 2>/dev/null \
| head -n1 || true)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The output of find_remote_tools is a JSON array of tool objects, not an object containing an items key. Using .items[]? in the jq filter will result in an empty string, causing the E2E test to fail to discover the tool and eventually timeout. It should be updated to use .[]? instead.

Suggested change
peer="$(printf '%s' "$tools" \
| jq -r '.items[]? | select(.tool_name=="calculator.add") | .peer_id' 2>/dev/null \
| head -n1 || true)"
peer="$(printf '%s' "$tools" \\
| jq -r '.[]? | select(.tool_name=="calculator.add") | .peer_id' 2>/dev/null \\
| head -n1 || true)"

Comment thread cmd/sam-node/main.go
Comment on lines +185 to +192
displayHub := hubAddr
if displayHub == "" {
if h, err := store.LoadHubURL(); err == nil && h != "" {
displayHub = h
} else {
displayHub = "https://bananas.sam-mesh.dev"
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The hubAddr variable is registered with a default value of DefaultHubURL ("http://localhost:8080"), meaning displayHub will never be empty under normal execution. As a result, the fallback block to load the stored hub URL or default to the public bananas mesh will never be executed. Consider checking if displayHub is equal to DefaultHubURL or empty.

Suggested change
displayHub := hubAddr
if displayHub == "" {
if h, err := store.LoadHubURL(); err == nil && h != "" {
displayHub = h
} else {
displayHub = "https://bananas.sam-mesh.dev"
}
}
displayHub := hubAddr
if displayHub == DefaultHubURL || displayHub == "" {
if h, err := store.LoadHubURL(); err == nil && h != "" {
displayHub = h
} else {
displayHub = "https://bananas.sam-mesh.dev"
}
}

@aojea aojea merged commit 84887d7 into google:main Jun 29, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant